﻿/*
 * Copyright © 2010 Caduceuscoil. All rights reserved.
 * 
 * This file is part of Search Registry.
 * 
 * RegSearch is open-source software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free Software Foundation,
 * either version 2 of the License, or (at your option) any later version.
 * 
 * RegSearch is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with Velodoc XP Edition.
 * If not, see <http://www.gnu.org/licenses/>.
 *  
 */

/* CHANGE LOG
 * Last Modified: 10/22/2010
 * Modified By: CC.
 * -----------------------------------------
 * Initial Version: 10/11/2010
 * Created By: CC.
 * 
 * 
 * BUGS:
 * 
 * 
 * 
 * TODO:
 * 
 */
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace SearchRegistry
{
    /// <summary>
    /// 
    /// </summary>
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public class SearchImpersonation
    {
        /// <summary>
        /// Logon Providers
        /// </summary>
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_PROVIDER_WINNT40 = 2;
        const int LOGON32_PROVIDER_WINNT50 = 3;

        /// <summary>
        /// Logon Types
        /// </summary>
        const int LOGON32_LOGON_BATCH = 1;
        const int LOGON32_LOGON_INTERACTIVE = 2;
        const int LOGON32_LOGON_NETWORK = 3;
        const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
        const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="lpszUsername"></param>
        /// <param name="lpszDomain"></param>
        /// <param name="lpszPassword"></param>
        /// <param name="dwLogonType"></param>
        /// <param name="dwLogonProvider"></param>
        /// <param name="phToken"></param>
        /// <returns></returns>
        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        extern static bool CloseHandle(IntPtr handle);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ExistingTokenHandle"></param>
        /// <param name="SECURITY_IMPERSONATION_LEVEL"></param>
        /// <param name="DuplicateTokenHandle"></param>
        /// <returns></returns>
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static IntPtr GetUserToken()
        {
            return WindowsIdentity.GetCurrent().Token;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="pass"></param>
        /// <returns></returns>
        public static IntPtr GetUserToken(string user, string pass)
        {
            return GetUserToken(user, pass, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="pass"></param>
        /// <param name="domain"></param>
        /// <returns></returns>
        public static IntPtr GetUserToken(string user, string pass, string domain)
        {
            bool retVal;
            IntPtr tokenHandle = IntPtr.Zero;
            IntPtr dupToken = IntPtr.Zero;

            if (string.IsNullOrEmpty(user)) { return tokenHandle; }
            
            //Try to logon the Windows 2000 and newer method
            retVal = LogonUser(user, domain, pass, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);
            if (false == retVal)//Fall back to the Windows XP method
                retVal = LogonUser(user, domain, pass, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

            //Retrieve the token for the remote session
            retVal = DuplicateToken(tokenHandle, 2, ref dupToken);
            
            //The logon process failed
            if (false == retVal)
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            
            //Return the session token
            return dupToken;
        }
        /// <summary>
        /// 
        /// </summary>
        public static void CloseToken(IntPtr token)
        {
            //
            if (null != token)
                if (IntPtr.Zero != token)
                    CloseHandle(token);
            //
            token = IntPtr.Zero;
        }
    }
}
